/**
 * @file list.c
 * @author your name (you@domain.com)
 * @brief 实现list数据结构
 * @version 0.1
 * @date 2023-10-23
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#include <stdio.h>
#include <stdlib.h>

#include "list.h"

#ifdef COMPILE_DEFINITIONS_LIST

/**
 * @brief list的单个节点
 * 
 */
typedef struct node{
    void *data;
    struct node *next;
}node;

/**
 * @brief list结构体
 * 
 */
struct list {
    node *start;
    node *end;
    int64_t total;
};

/**
 * @brief list句柄初始化
 * 
 * @param handler 初始化句柄，需要传入二级指针，内部自动申请内存
 * @return int 
 */
int list_init(list **handler) {
    if(handler == NULL) {
        return LIST_BAD_INPUT_DATA;
    }

    *handler = (list*)malloc(sizeof(list));

    if((*handler) == NULL) {
        return LIST_MALLOC_FAILED;
    }

    (*handler)->start = (node*)malloc(sizeof(node));
    (*handler)->end = (*handler)->start;
    (*handler)->total = 0;

    return LIST_OK;
}

/**
 * @brief list添加一个元素，需要element需要外部malloc申请内存
 * 
 * @param handler list句柄
 * @param element 任意类型的指针，但是需要在接口外部malloc内存
 * @return int 
 */
int list_add(list *handler, void *element) {
    node *n = NULL;

    if(handler == NULL || element == NULL) {
        return LIST_BAD_INPUT_DATA;
    }

    n = (node *)malloc(sizeof(node));

    if(n == NULL) {
        return LIST_MALLOC_FAILED;
    }

    n->data = element;
    n->next = NULL;
    handler->end->next = n;
    handler->end = n;

    handler->total++;

    return LIST_OK;
}

/**
 * @brief 添加到指定位置，index从1开始计数
 * 
 * @param handler list句柄
 * @param index 具体位置，从1开始
 * @param element 任意类型的指针，但是需要在接口外部malloc
 * @return int 
 */
int list_add_at(list *handler, int64_t index, void *element) {
    int i = 0;
    node *head = NULL;
    node *n = NULL;

    if(handler == NULL || index <= 0 || element == NULL) {
        return LIST_BAD_INPUT_DATA;
    }

    if(index > handler->total) {
        return LIST_INDEX_BIGGER_THAN_MAX;
    }

    head = handler->start;

    for(i = 1; i < index; i++) {
         head = head->next;
    }

    n = (node *)malloc(sizeof(node));
    n->next = head->next;
    n->data = element;
    head->next = n;

    handler->total++;

    return LIST_OK;
}

/**
 * @brief 替换element
 * 
 * @param handler list句柄
 * @param index 位置
 * @param element_in 替换进入的内容
 * @param element_out 替换输出的内容
 * @return int 
 */
int list_replace_at(list *handler, int64_t index, void *element_in, void **element_out) {
    int i = 0;
    node *head = NULL;
    
    if(handler == NULL || index <= 0 || element_in == NULL || element_out == NULL || (*element_out) == NULL) {
        return LIST_BAD_INPUT_DATA;
    }

    if(index > handler->total) {
        return LIST_INDEX_BIGGER_THAN_MAX;
    }

    head = handler->start;
    for(i = 1; i < index; i++) {
        head = head->next;
    }

    (*element_out) = head->data;
    head->data = element_in;

    return LIST_OK;
}

/**
 * @brief 获得list的大小并存放到size中
 * 
 * @param handler list句柄
 * @param size 大小
 * @return int 
 */
int list_size(list *handler, int64_t *size) {
    if(handler == NULL || size == NULL) {
        return LIST_BAD_INPUT_DATA;
    }
    
    *size = handler->total;
    return LIST_OK;
}

/**
 * @brief 获得list中index处的一个元素，下标从1开始计算
 * 
 * @warning 获得的element是一个浅拷贝，仅仅只是把指针返回出来了，如果外部释放会导致程序崩溃；而且此处的element需要和add的时候是同样的类型
 * 
 * @param handler list句柄
 * @param index 位置
 * @param element 获得元素，返回的是指针
 * @return int 
 */
int list_get_at(list *handler, int64_t index, void **element) {
    int i = 0;
    node *head = NULL;

    if(handler == NULL || index <= 0 || element == NULL) {
        return LIST_BAD_INPUT_DATA;
    }

    if(index > handler->total) {
        return LIST_INDEX_BIGGER_THAN_MAX;
    }

    head = handler->start->next;

    for(i = 1; i < index; i++) {
        head = head->next;
    }

    *element = head->data;

    return LIST_OK;
}

/**
 * @brief list导出，将handler中的所有内容导出到export_arr中，需要确保前后元素类型一致
 * 
 * @param handler list句柄
 * @param export_arr 导出的buffer
 * @param arr_size buffer大小
 * @param arr_length buffer输出长度
 * @return int 
 */
int list_export(list *handler, void *export_arr[], int64_t arr_size, int64_t *arr_length) {
    node *head = handler->start->next;
    int i = 0;

    if(handler == NULL || export_arr == NULL || handler->total <= 0) {
        return LIST_BAD_INPUT_DATA;
    }

    if(handler->total > arr_size) {
        return LIST_BUFFER_TOO_SMALL;
    }

    for(i = 0; i < handler->total && head != NULL; i++, head = head->next) {
        export_arr[i] = head->data;
    }

    *arr_length = handler->total;

    return LIST_OK;
}

/**
 * @brief 释放list中所有的内存，并将handler指向NULL
 * 
 * @param handler list句柄
 * @return int 
 */
int list_free_all(list **handler) {
    node *head = NULL;
    node *temp = NULL;

    if(handler == NULL || *handler == NULL) {
        return LIST_BAD_INPUT_DATA;
    }

    head = (*handler)->start;

    while(head != NULL) {
        if(head->data != NULL) {
            free(head->data);
        }
        temp = head;
        head = head->next;
        free(temp);
    }

    (*handler)->start = NULL;
    (*handler)->end = NULL;

    free((*handler));

    (*handler) = NULL;

    return LIST_OK;
}

/**
 * @brief 释放index处的内容
 * 
 * @param handler list句柄
 * @param index 位置
 * @return int 
 */
int list_free_at(list *handler, int index) {
    int i = 0;
    node *head = NULL;
    node *temp = NULL;

    if(handler == NULL || index <= 0) {
        return LIST_BAD_INPUT_DATA;
    }

    if(handler->total < index) {
        return LIST_INDEX_BIGGER_THAN_MAX;
    }

    head = handler->start;

    for(i = 1; i < index; i++) {
        head = head->next;
    }

    temp = head->next;
    head->next = temp->next;
    free(temp->data);
    free(temp);

    handler->total--;

    if(head->next == NULL) {    // 如果删除最后一个节点，则需要更新end指针
        handler->end = head;
    }

    return LIST_OK;
}
#endif